<?php

namespace app\common\tools;

use app\common\tools\VersionModel;
use app\common\exception\ThrowException;
use think\Request;
use think\Response;

class VersionHandle
{
    // 抛异常提示消息
    const NOT_NULL_RESPONSE_MSG = 1000001;
    const MUST_EXTENDS_VERSION_BASE_MSG = 1000002;
    const NOT_FOUND_VERSION_MSG = 1000003;
    const DEFAULT_VERSION = [10000];
    /**
     * 版本控制器所在命名空间
     * @var string
     */
    protected $version_namespace = 'app\\api\\version\\';
    // 起始版本号
    protected $floor_version = 10000;
    // 所有版本号
    protected $version = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    protected function __construct(Array $version = [])
    {
        $this->version = $version ? $version : self::DEFAULT_VERSION;
    }

    /**
     * 启动方法
     * @param array $version
     * @return mixed
     * @throws \Exception
     */
    public static function init(Array $version = [])
    {
        
        if (empty($version)) {
            // 从数据库里获取版本信息
            $version = self::getVersionByDb();
        }

        $self = new self($version);
        return $self->run();
    }

    /**
     * 版本控制运行方法
     * @return mixed
     * @throws \Exception
     */
    protected function run(): Response
    {
        $version = request()->header('version');
        if (empty($version)) {
            // 1、抛权限异常，说明缺少版本号    2、默认赋10000
            ThrowException::version(self::NOT_FOUND_VERSION_MSG);
        }

        rsort($this->version);
        $pathinfo = request()->pathinfo();
        // app\api\version\record\add\V
        $namespace = $this->version_namespace . str_replace('/', '\\', $pathinfo) . '\V';
        foreach ($this->version as $value) {
            if ($this->compareV($version, $value)){
                    $new_namespace = $namespace . $value;
                    $res = $this->toControllerByV($new_namespace);
                    if ($res) return $res;
            }

        }

        $res = $this->toControllerByV($namespace);
        if ($res) return $res;
        ThrowException::version(self::NOT_FOUND_VERSION_MSG);
    }

    /**
     * 传入版本号与历史版本号比较
     * @param $new_version
     * @param $old_version
     * @return bool
     */
    protected function compareV($new_version, $old_version)
    {
        return $new_version >= $old_version && $old_version != $this->floor_version;
    }

    /**
     * 通过版本号找到控制器
     * @param String $namespace
     * @return null
     * @throws \Exception
     */
    protected function toControllerByV(String $namespace)
    {
        if (!class_exists($namespace)) {
            return null;
        }

        try {
            $responseObj = $namespace::init();
        } catch (\Throwable $th) {
            ThrowException::version(self::MUST_EXTENDS_VERSION_BASE_MSG);
        }

        $response = $responseObj->run();
        if (!$response) {
            ThrowException::version(self::NOT_NULL_RESPONSE_MSG);
        }

        return  $response;
    }

    /**
     * 从db获取版本信息
     * @return array|int[]
     */
    protected static function getVersionByDb()
    {
        try {
            $res = VersionModel::order('version_code asc')->column('version_code');
            return empty($res) ? self::DEFAULT_VERSION : $res;
        } catch (\Throwable $th) {}
        return self::DEFAULT_VERSION;
    }
    
}
